package gis

import (
	"dgo/goutils/utils"
	"errors"
	"strconv"
	"strings"
	"time"
)

/*
**

	利用线性内插法产生中间点
	路径点最好是一个闭环的路径
	传入gen.getPoint(time.Now().Unix())
*/
type GenPoint struct {
	startT uint64
	maxT   uint64
	fixedX []float64
	fixedY []float64
	fixedT []uint64

	// 计算时间点, 返回该段距离需要多少时间(可以是秒，也可以是毫秒)， 推荐用s， 取决于获取时传入的t
	onCalcuTEvent func(x1, y1, x2, y2 float64) uint64
	Recycle       bool
	lastIdx       int
}

func NewGenPoint(startT uint64, oncalcuT func(x1, y1, x2, y2 float64) uint64) *GenPoint {
	return &GenPoint{startT: startT, onCalcuTEvent: oncalcuT}
}

func (this *GenPoint) MaxT() uint64 {
	return this.maxT
}

func (this *GenPoint) AddFxiedPointFromParseText(text string, errCb func(itmText string) bool) int {
	text = strings.ReplaceAll(text, ";", "\n")
	text = strings.ReplaceAll(text, "\r\n", "\n")

	text = strings.ReplaceAll(text, ",", " ")
	text = strings.ReplaceAll(text, "\t", " ")
	text = strings.ReplaceAll(text, "  ", " ")
	text = strings.ReplaceAll(text, "  ", " ")

	strs := strings.Split(text, "\n")
	r := 0
	for i := 0; i < len(strs); i++ {
		xystr := utils.Trim(strs[i])
		if len(xystr) == 0 {
			continue
		}
		strs2 := strings.SplitN(xystr, " ", 2)
		if len(strs2) == 1 {
			if errCb != nil {
				if !errCb((xystr)) {
					break
				}
			}
			continue
		}

		x1, err := strconv.ParseFloat(utils.Trim(strs2[0]), 64)
		if err != nil {
			if errCb != nil {
				if !errCb((xystr)) {
					break
				}
			}
			continue
		}
		y1, err := strconv.ParseFloat(utils.Trim(strs2[1]), 64)
		if err != nil {
			if errCb != nil {
				if !errCb((xystr)) {
					break
				}
			}
			continue
		}

		err = this.AddFxiedPoint(x1, y1)
		if err != nil {
			if errCb != nil {
				if !errCb((xystr)) {
					break
				}
			}
			continue
		}

		r++
	}

	return r

}

func (this *GenPoint) AddFxiedPoint(x, y float64) error {
	if this.onCalcuTEvent == nil {
		return errors.New("onCalcuTEvent is nil, 无法计算时间刻度")
	}

	if len(this.fixedX) == 0 {
		this.maxT = this.startT
	} else {
		l := len(this.fixedX)
		// 最后一个
		T := this.onCalcuTEvent(this.fixedX[l-1], this.fixedY[l-1], x, y)
		this.maxT = this.fixedT[l-1] + T
	}
	this.fixedT = append(this.fixedT, this.maxT)
	this.fixedX = append(this.fixedX, x)
	this.fixedY = append(this.fixedY, y)
	return nil
}

func (this *GenPoint) getBegin(t uint64) (idx int) {
	//t = t % this.maxT // 取余数

	// 从上次开始寻找
	for i := this.lastIdx; i < len(this.fixedT); i++ {
		if this.fixedT[i] == t {
			this.lastIdx = i
			return i
		} else if this.fixedT[i] > t {
			this.lastIdx = i - 1
			if this.fixedT[this.lastIdx] > t { // 可能中间断线很长时间. 导致数据没对准, 跳出循环, 从0开始查找
				break
			}
			return i - 1
		}
	}

	if this.lastIdx > 0 {
		// 从头再找一遍
		for i := 0; i < this.lastIdx; i++ {
			if this.fixedT[i] == t {
				this.lastIdx = i
				return i
			} else if this.fixedT[i] > t {
				this.lastIdx = i - 1
				return i - 1
			}
		}
	}

	return -1
}

/*
会循环获取点
*/
func (this *GenPoint) GenPoint(t uint64) (x, y float64, ok bool) {
	if this.Recycle {
		t = t % this.maxT // 取余数 循环
	} else {
		if t > this.maxT {
			t = this.maxT
		}
	}

	idx := this.getBegin(t)
	if idx == -1 {
		this.lastIdx = 0
		return 0, 0, false
	}

	x1, y1 := this.fixedX[idx], this.fixedY[idx]
	t1 := t - this.fixedT[idx]
	if t1 == 0 {
		return x1, y1, true
	}

	x2, y2 := this.fixedX[idx+1], this.fixedY[idx+1]
	T := float64(this.fixedT[idx+1] - this.fixedT[idx])
	x = x1 + (x2-x1)/T*float64(t1)
	y = y1 + (y2-y1)/T*float64(t1)
	return x, y, true
}

func (this *GenPoint) GenPointNowUnixSec() (x, y float64, ok bool) {
	t1 := time.Now().Unix()
	return this.GenPoint(uint64(t1))
}
